﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SmartCollector.Domain.Repository;
using System.Data.Linq;
using SmartCollector.Domain;
using HtmlParser.SiteManager;
using HtmlParser;
using SmartCollector.Domain.Entity;

namespace SmartCollector
{
    public partial class CollectorForm : Form
    {
        #region Members
        private SiteRepository m_siteRepository;
        private ItemRepository m_itemRepository;
        private RssReader.RssReader m_rssReader = new SmartCollector.RssReader.RssReader();
        private int m_selectedSite;
        private static int s_filename = 1;
        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the current site structure.
        /// </summary>
        /// <value>
        /// The current site structure.
        /// </value>
        public SiteItemStructure CurrentSiteStructure
        {
            get;
            set;
        }

        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="CollectorForm"/> class.
        /// </summary>
        public CollectorForm()
        {
            InitializeComponent();
            m_siteRepository = new SiteRepository();
            m_itemRepository = new ItemRepository();
        }
        #endregion

        #region Methods

        #region Main Tab

        /// <summary>
        /// Handles the Load event of the CollectorForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CollectorForm_Load(object sender, EventArgs e)
        {
            LoadTreeSites();
            InitSites();
        }

        /// <summary>
        /// Loads the site tree.
        /// </summary>
        private void LoadTreeSites()
        {
            TreeNode root = new TreeNode("Root");
            root.Tag = 0;
            foreach (var siteItem in m_siteRepository.Sites)
            {
                TreeNode siteNode = new TreeNode(siteItem.SiteName);
                siteNode.Tag = new NodeInfo { SiteId = siteItem.ID, Level = TreeNodeLevel.Site };

                foreach (var rss in siteItem.tbl_LinkRSSes)
                {
                    TreeNode rssNode = new TreeNode(rss.LinkRSS);
                    rssNode.Tag = new NodeInfo
                    {
                        Level = TreeNodeLevel.Rss,
                        CategoryId = (int)rss.CategoryId,
                        SiteId = siteItem.ID
                    };

                    siteNode.Nodes.Add(rssNode);
                }
                root.Nodes.Add(siteNode);
            }
            root.Expand();
            treeView1.Nodes.Add(root);
        }

        /// <summary>
        /// Handles the Click event of the m_bntStartCollecting control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnItemCollecting(object sender, EventArgs e)
        {
            TreeNode root = treeView1.Nodes[0];
            progressBar1.Visible = true;
            m_lblState.Visible = true;
            foreach (TreeNode siteNode in root.Nodes)
            {
                NodeInfo siteInfo = siteNode.Tag as NodeInfo;
                SiteItemStructure siteStructure = SiteStructureManager.Instance.GetSiteItemStructure(siteInfo.SiteId);
                foreach (TreeNode rssNode in siteNode.Nodes)
                {
                    NodeInfo rssNodeInfo = rssNode.Tag as NodeInfo;
                    ReadFeed(rssNode.Text, rssNodeInfo.CategoryId, siteStructure);
                }
            }
            progressBar1.Visible = false;
            m_lblState.Visible = false;
            m_itemRepository.SubmitChanges();
        }

        /// <summary>
        /// Reads the feed.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="categoryId">The category id.</param>
        /// <param name="siteStructure">The site structure.</param>
        private void ReadFeed(string url, int categoryId, SiteItemStructure siteStructure)
        {
            m_rssReader.FeedLoaded += OnRssFeedLoaded;
            m_rssReader.ItemAdded += OnItemAdded;
            RssReader.RssFeed feed = m_rssReader.Retrieve(url);
            progressBar1.Value = 0;
            progressBar1.Maximum = feed.Items.Count;
            m_lblState.Text = string.Format("Collecting: {0} at {1}", GetCategoryName(categoryId),
                siteStructure.SiteDomainName);
            foreach (RssReader.RssItem item in feed.Items)
            {
                string dateTime = !string.IsNullOrEmpty(item.Pubdate)?
                    item.Pubdate :feed.PubDate;
                DateTime time;
                if (!DateTime.TryParse(dateTime, out time))
                {
                    time = DateTime.Now;
                }
                ReadNewItemFromRss(item, categoryId, siteStructure, time);
                progressBar1.Value++;
            }
        }

        /// <summary>
        /// Gets the name of the category.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        private string GetCategoryName(int id)
        {
            //TODO: Implement this correctly
            return id.ToString();
        }

        /// <summary>
        /// Filters the new item.
        /// </summary>
        /// <param name="rssItem">The RSS item.</param>
        /// <param name="categoryId">The category id.</param>
        /// <param name="siteStructure">The site structure.</param>
        private void ReadNewItemFromRss(RssReader.RssItem rssItem, int categoryId, 
            SiteItemStructure siteStructure, DateTime time)
        {
            tbl_Item item = FilterManager.FilterManager.Instance.GetNewItem(rssItem, categoryId, siteStructure,time);
            SaveItemToXml(item);
            m_itemRepository.AddItem(item);
        }

        /// <summary>
        /// Called when [RSS feed loaded].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnRssFeedLoaded(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// Saves the item to XML.
        /// </summary>
        /// <param name="item">The item.</param>
        private void SaveItemToXml(tbl_Item item)
        {
            //SmartCollector.GUI.Helpers.DeSerializeHelper.Deserialize(item,string.Format("Items/{0}.xml",s_filename++));
            //SmartCollector.GUI.Helpers.DeSerializeHelper.SaveNewItemToFile(string.Format("Items/{0}.html", s_filename++), item);
        }

        /// <summary>
        /// Called when [item added].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnItemAdded(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Handles the Resize event of the CollectorForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CollectorForm_Resize(object sender, EventArgs e)
        {
            tabControl1.Refresh();
        }

        #endregion Main Tab

        #region Config Page Tab

        /// <summary>
        /// Loads the sites.
        /// </summary>
        private void InitSites()
        {
            m_cmbSites.DataSource = m_siteRepository.Sites.ToList();
            m_cmbSites.DisplayMember = "SiteName";
        }

        /// <summary>
        /// Called when [site changed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnSiteChanged(object sender, EventArgs e)
        {
            var selectedItem = m_cmbSites.SelectedItem as tbl_ReferenceSite;
            if (selectedItem != null)
            {
                m_lblCurrentSite.Text = string.Format("Site : {0}", selectedItem.SiteName);
                LoadSiteConfig(selectedItem.ID,selectedItem.Url);
            }
        }

        /// <summary>
        /// Loads the site config.
        /// </summary>
        /// <param name="siteId">The site id.</param>
        private void LoadSiteConfig(int siteId,string siteName)
        {
            if (CurrentSiteStructure != null && CurrentSiteStructure.IsDirty)
            {
                SiteStructureManager.Instance.RegisterNewSiteStructure(CurrentSiteStructure);
            }
            m_treeSiteStructure.Nodes.Clear();
            SiteItemStructure oldStructure =
                SiteStructureManager.Instance.GetSiteItemStructure(siteId);
            if (oldStructure != null)
            {
                CurrentSiteStructure = oldStructure;
            }
            else
            {
                CurrentSiteStructure = new SiteItemStructure()
                {
                    SiteId = siteId,
                    SiteDomainName = siteName,
                };
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Refreshes the sites structure tree.
        /// </summary>
        private void RefreshSitesStructureTree()
        {
            m_treeSiteStructure.Nodes.Clear();
            if (CurrentSiteStructure == null)
            {
                return;
            }
            TreeNode siteNode = new TreeNode(CurrentSiteStructure.SiteDomainName);
            foreach (RegionArea region in Enum.GetValues(typeof(RegionArea)))
            {
                TreeNode regionNode = new TreeNode(region.ToString());
                TagSelector selector = CurrentSiteStructure.GetConstraint(region);
                if (selector != null)
                {
                    foreach (KeyValuePair<string, string> constraint in selector.ConstraintCollections)
                    {
                        regionNode.Nodes.Add(
                            new TreeNode(string.Format("{0} : {1}", constraint.Key, constraint.Value)));
                    }
                }
                siteNode.Nodes.Add(regionNode);
            }
            siteNode.ExpandAll();
            m_treeSiteStructure.Nodes.Add(siteNode);
        }

        /// <summary>
        /// Called when [add boundary structure].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnAddBoundaryStructure(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtBoundaryKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtBoundaryValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.Boundary,
                    m_txtBoundaryKey.Text.Trim(),
                    m_txtBoundaryValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Adds the title structure.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void AddTitleStructure(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtTitleKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtTitleValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.Title,
                    m_txtTitleKey.Text.Trim(),
                    m_txtTitleValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Adds the description structure.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void AddDescriptionStructure(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtDescriptionKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtDescriptionValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.Description,
                    m_txtDescriptionKey.Text.Trim(),
                    m_txtDescriptionValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Adds the content struture.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void AddContentStruture(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtContentKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtContentValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.Content,
                    m_txtContentKey.Text.Trim(),
                    m_txtContentValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Handles the Click event of the m_bntAddAuthor control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void m_bntAddAuthor_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtAuthorKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtAuthorValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.Author,
                    m_txtAuthorKey.Text.Trim(),
                    m_txtAuthorValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Handles the Click event of the m_bntAddSource control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void m_bntAddSource_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtSourceKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtSourceValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.Source,
                    m_txtSourceKey.Text.Trim(),
                    m_txtSourceValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Handles the Click event of the m_bntAddNearestBound control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void m_bntAddNearestBound_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_txtNearestKey.Text.Trim())
                || string.IsNullOrEmpty(m_txtNearestValue.Text.Trim()))
            {
                MessageBox.Show("Invalid Input!");
                return;
            }
            if (CurrentSiteStructure != null)
            {
                CurrentSiteStructure.AddConstraint(RegionArea.NearestBoundary,
                    m_txtNearestKey.Text.Trim(),
                    m_txtNearestValue.Text.Trim());
            }
            RefreshSitesStructureTree();
        }

        /// <summary>
        /// Called when [save site config].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnSaveSiteConfig(object sender, EventArgs e)
        {
            SiteStructureManager.Instance.SaveToXml();
        }

        #endregion

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Form.Closing"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.ComponentModel.CancelEventArgs"/> that contains the event data.</param>
        protected override void OnClosing(CancelEventArgs e)
        {
            if (SiteStructureManager.Instance.IsDirty)
            {
                DialogResult rs = MessageBox.Show("Do you want to save all site Structure Config?","Confirm Save",MessageBoxButtons.YesNo);
                if (rs == System.Windows.Forms.DialogResult.Yes)
                {
                    SiteStructureManager.Instance.SaveToXml();
                }
            }
            base.OnClosing(e);
        }
        #endregion
       
        private void m_btnAddSite_Click(object sender, EventArgs e)
        {
            SmartCollector.GUI.AddSite addsite = new GUI.AddSite();
            addsite.ShowDialog();
            LoadTreeSites();
            InitSites();
           
           
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class NodeInfo
    {
        public int CategoryId
        {
            get;
            set;
        }
        public int SiteId
        {
            get;
            set;
        }
        public TreeNodeLevel Level
        {
            get;
            set;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public enum TreeNodeLevel
    {
        Root,
        Site,
        Rss,
        Category
    }
}
